package com.fdb.efp.console.api.rest;

import com.alibaba.fastjson.JSON;
import com.fdb.basic.framework.core.constant.ApplicationConstance;
import com.fdb.basic.framework.core.constant.DataRuleType;
import com.fdb.basic.framework.core.constant.ResponseData;
import com.fdb.basic.framework.core.util.BeanUtility;
import com.fdb.basic.framework.core.util.DateUtility;
import com.fdb.basic.framework.core.util.StringUtil;
import com.fdb.basic.framework.core.util.TimeUtil;
import com.fdb.basic.framework.web.controller.AbstractController;
import com.fdb.efp.console.service.facade.LoanRepayDetailService;
import com.fdb.efp.console.service.vo.LoanRepayDetailVO;
import com.fdb.efp.console.api.service.RiskmUtilService;
import com.fdb.efp.console.common.RiskColltConstant;
import com.fdb.efp.console.service.facade.ColltTaskDistrService;
import com.fdb.efp.console.service.facade.ColltTaskInfoService;
import com.fdb.efp.console.service.facade.CooprOrgInfoService;
import com.fdb.efp.console.service.vo.ColltTaskDistrVO;
import com.fdb.efp.console.service.vo.ColltTaskInfoVO;
import com.fdb.efp.console.service.vo.CooprOrgInfoVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/api")
public class OutColltTaskDistrController extends AbstractController {

    @Autowired
    @Qualifier("colltTaskDistrService")
    private ColltTaskDistrService colltTaskDistrService;

    @Autowired
    @Qualifier("colltTaskInfoService")
    private ColltTaskInfoService colltTaskInfoService;

    @Autowired
    @Qualifier("cooprOrgInfoService")
    private CooprOrgInfoService cooprOrgInfoService;

    @Autowired
    private RiskmUtilService riskmUtilService;

    @Autowired
    @Qualifier("loanRepayDetailService")
    private LoanRepayDetailService loanRepayDetailService;

    private final static String oneHand = RiskColltConstant.STD_HANDLE_TYPE_01;
    private final static String twoHand = RiskColltConstant.STD_HANDLE_TYPE_02;
    private final static String threeHand = RiskColltConstant.STD_HANDLE_TYPE_03;
    private final static String longHand = RiskColltConstant.STD_HANDLE_TYPE_04;

    private final static List<String> allHandTypeList = Arrays.asList(oneHand, twoHand, threeHand, longHand);

    /**
     * 列表数据查询
     *
     * @param vo
     * @return
     */
    @RequestMapping(value = "/collt/task/distrs", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<List<ColltTaskDistrVO>> queryColltTaskDistrAll(@RequestBody ColltTaskDistrVO vo) {
        List<ColltTaskDistrVO> outputVo = null;
        /**Map<String,String> dataRuleTypeMap = sRoleDataRuleService.getDataRuleType(httpRequest.getRequestURI(), getUserRoles());
         vo.setPrdCodebyBaseInfo(dataRuleTypeMap == null ? null:dataRuleTypeMap.get(PubConstant.PRD_CODE));
         DataRuleType dataRuleType = DataRuleType.getDataRuleType(dataRuleTypeMap == null ? null:dataRuleTypeMap.get(PubConstant.PERMIS_TYPE));*/
        DataRuleType dataRuleType = DataRuleType.getDataRuleType("01");
        setUserInfoToVO(vo);
        if (!StringUtil.isNullorBank(vo.getExportFlag()) && "exp".equals(vo.getExportFlag())) {
            logger.info("开始导出数据！");
            // 根据权限方案调用不同的方案进行数据导出
            switch (dataRuleType) {
                case Owner:
                    outputVo = colltTaskDistrService.queryExAllOwner(vo);
                    break;
                case CurrOrg:
                    outputVo = colltTaskDistrService.queryExAllCurrOrg(vo);
                    break;
                case CurrDownOrg:
                    outputVo = colltTaskDistrService.queryExAllCurrDownOrg(vo);
                    break;
                default:
                    outputVo = colltTaskDistrService.queryExAllCurrOrg(vo);
                    break;
            }
        } else {
            logger.info("开始查询数据！");
            // 根据权限方案调用不同的方案进行数据查询
            switch (dataRuleType) {
                case Owner:
                    outputVo = colltTaskDistrService.queryAllOwner(vo);
                    break;
                case CurrOrg:
                    outputVo = colltTaskDistrService.queryAllCurrOrg(vo);
                    break;
                case CurrDownOrg:
                    outputVo = colltTaskDistrService.queryAllCurrDownOrg(vo);
                    break;
                default:
                    outputVo = colltTaskDistrService.queryAllCurrOrg(vo);
                    break;
            }
        }
        return getResponseData(outputVo);

    }

    /**
     * 根据主键查询详情
     *
     * @return
     */
    @RequestMapping(value = "/collt/task/distr", method = RequestMethod.GET)
    public @ResponseBody
    ResponseData<ColltTaskDistrVO> queryByPk() {
        ColltTaskDistrVO inVo = new ColltTaskDistrVO();
        ColltTaskDistrVO outputVo = colltTaskDistrService.queryByPk(inVo);
        return getResponseData(outputVo);

    }

    /**
     * 根据主键删除信息
     *
     * @return
     */
    @RequestMapping(value = "/collt/task/distr", method = RequestMethod.DELETE)
    public @ResponseBody
    ResponseData<Integer> deleteByPk(@RequestBody ColltTaskDistrVO inColltTaskDistrVo) {
        int outputVo = colltTaskDistrService.deleteByPk(inColltTaskDistrVo);
        return getResponseData(outputVo);

    }

    /**
     * 根据主键更新信息
     *
     * @param inColltTaskDistrVo
     * @return
     */
    @RequestMapping(value = "/collt/task/distr", method = RequestMethod.PUT)
    public @ResponseBody
    ResponseData<Integer> updateByPk(@RequestBody ColltTaskDistrVO inColltTaskDistrVo) {
        int outputVo = colltTaskDistrService.updateByPk(inColltTaskDistrVo);
        return getResponseData(outputVo);

    }

    /**
     * 新增数据
     *
     * @param inColltTaskDistrVo
     * @return
     */
    @RequestMapping(value = "/collt/task/distr", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<Integer> insertColltTaskDistr(@RequestBody ColltTaskDistrVO inColltTaskDistrVo) {
        int outputVo = colltTaskDistrService.insertColltTaskDistr(inColltTaskDistrVo);
        return getResponseData(outputVo);

    }

    /**
     * 查询分案审批信息
     *
     * @param vo
     * @return
     */
    @RequestMapping(value = "/collt/task/distr/appr", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<List<ColltTaskDistrVO>> showColltTaskDistrAppr(@RequestBody ColltTaskDistrVO vo) {
        List<ColltTaskDistrVO> outputVo = colltTaskDistrService.queryByCondition(vo);
        return getResponseData(outputVo);
    }

    /**
     * 通过条件分页查询，催收任务分配信息
     *
     * @param vo
     * @return
     */
    @RequestMapping(value = "/collt/task/distr/by/Condition", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<List<ColltTaskDistrVO>> qryColltTaskDistr(@RequestBody ColltTaskDistrVO vo) {
        List<ColltTaskDistrVO> outputVo = colltTaskDistrService.queryInfosByVo(vo);
        riskmUtilService.displayOrgName(outputVo, "opOrgCode", "opOrgName");
        riskmUtilService.displayUserName(outputVo, "opUserCode", "opUserName");
        return getResponseData(outputVo);
    }

    /**
     * 佣金试算所属数据
     *
     * @param colltTaskDistrVO
     * @return
     */
    @RequestMapping(value = "/collt/task/comm", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<List<ColltTaskDistrVO>> queryDatas4commByPage(@RequestBody ColltTaskDistrVO colltTaskDistrVO) {
        List<ColltTaskDistrVO> outputVo = Optional.ofNullable(colltTaskDistrService.queryDatas4commByPage(colltTaskDistrVO)).orElseGet(ArrayList::new);
        addCooprType(outputVo);
        riskmUtilService.displayOrgName(outputVo, "aprvUserOrg", "aprvUserOrgName");
        return getResponseData(outputVo);
    }

    private void addCooprType(List<ColltTaskDistrVO> outputVo) {
        outputVo.forEach(item -> {
            CooprOrgInfoVO cooprOrgInfoVO = new CooprOrgInfoVO();
            cooprOrgInfoVO.setCooprOrgNo(item.getOutsOrgCode());
            CooprOrgInfoVO rs = Optional.ofNullable(cooprOrgInfoService.queryByPk(cooprOrgInfoVO)).orElseGet(CooprOrgInfoVO::new);
            item.setCooprOrgType(rs.getCooprOrgType());
        });
    }

    /**
     * 佣金试算金额计算
     * 目前涉及模块：委外催收、诉讼催收
     * @param colltTaskDistrVO
     * @return
     */
    @RequestMapping(value = "/collt/task/comm/calcul", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<ColltTaskDistrVO> calculations(@RequestBody ColltTaskDistrVO colltTaskDistrVO) {
        ColltTaskDistrVO outputVo = null;
        try {
            outputVo = getCalculRs(colltTaskDistrVO);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseData.create(null, ApplicationConstance.FAILURE, e.getMessage(), false);
        }
        return getResponseData(outputVo);
    }

    private ColltTaskDistrVO getCalculRs(ColltTaskDistrVO colltTaskDistrVO) throws Exception {
        ColltTaskDistrVO result = new ColltTaskDistrVO();

        BeanUtility.beanCopy(colltTaskDistrVO, result);
        String colltBatchNo = colltTaskDistrVO.getColltBatchNo();
        String outsOrgCode = colltTaskDistrVO.getOutsOrgCode();
//        String trialDate = "";
//
//        if(StringUtil.isNullorBank(colltTaskDistrVO.getAprvTime())){
//            throw new Exception("业务数据有误，分配时间不该为空");
//        }else{
//            trialDate = colltTaskDistrVO.getAprvTime().substring(0, 10);
//        }

        //查询催收任务信息
        ColltTaskInfoVO colltTaskInfoVO = new ColltTaskInfoVO();
        colltTaskInfoVO.setColltBatchNo(colltBatchNo);
        colltTaskInfoVO.setOutsOrgCode(outsOrgCode);
        List<ColltTaskInfoVO> colltTaskInfoVOList = colltTaskInfoService.queryAllByCondition(colltTaskInfoVO);
        if(Objects.isNull(colltTaskInfoVOList)){
            throw new Exception("根据分配批次号: "+ colltBatchNo + "，机构编号: "+outsOrgCode + "，获取到的催收任务信息为空");
        }

        //查询分案信息，用以展示
        List<ColltTaskDistrVO> colltTaskDistrVOList = colltTaskDistrService.queryAllByCondition(colltTaskDistrVO);

        //处理委外机构类型
        if (RiskColltConstant.COOPR_ORG_TYPE_001.equals(colltTaskDistrVO.getCooprOrgType())) {
            colltTaskDistrVOList.forEach(ctdv -> {
                if (RiskColltConstant.STD_HANDLE_TYPE_01.equals(ctdv.getOutsHdleType())) {
                    result.setPrimCommOverLmtTotal(ctdv.getDistrLmt() == null ? BigDecimal.ZERO : ctdv.getDistrLmt());
                } else if (RiskColltConstant.STD_HANDLE_TYPE_02.equals(ctdv.getOutsHdleType())) {
                    result.setSecdCommOverLmtTotal(ctdv.getDistrLmt() == null ? BigDecimal.ZERO : ctdv.getDistrLmt());
                } else if (RiskColltConstant.STD_HANDLE_TYPE_03.equals(ctdv.getOutsHdleType())) {
                    result.setThdCommOverLmtTotal(ctdv.getDistrLmt() == null ? BigDecimal.ZERO : ctdv.getDistrLmt());
                } else if (RiskColltConstant.STD_HANDLE_TYPE_04.equals(ctdv.getOutsHdleType())) {
                    result.setLongAgeCommOverLmtTotal(ctdv.getDistrLmt() == null ? BigDecimal.ZERO : ctdv.getDistrLmt());
                }
            });

            //按委外经手类型，计算从分配日期开始，一个自然月内的总回收金额
            Map<String, BigDecimal> loanNosByHandTypeMap = getRepayTotalByHandType(colltTaskInfoVOList, DateUtility.getLastMonthSEDate(LocalDate.now()));
            result.setPrimCommLmtTotal(loanNosByHandTypeMap.get(RiskColltConstant.STD_HANDLE_TYPE_01));
            result.setSecdCommLmtTotal(loanNosByHandTypeMap.get(RiskColltConstant.STD_HANDLE_TYPE_02));
            result.setThdCommLmtTotal(loanNosByHandTypeMap.get(RiskColltConstant.STD_HANDLE_TYPE_03));
            result.setLongAgeCommLmtTotal(loanNosByHandTypeMap.get(RiskColltConstant.STD_HANDLE_TYPE_04));
        }
        //处理诉讼机构类型
        else if (RiskColltConstant.COOPR_ORG_TYPE_002.equals(colltTaskDistrVO.getCooprOrgType())) {
            result.setDistrLmt(colltTaskDistrVOList.get(0).getDistrLmt());
            result.setCommLmtTotal(getRepayTotal(colltTaskInfoVOList, DateUtility.getLastMonthSEDate(LocalDate.now())));
        }
        else{
            throw new Exception("现阶段只支持对委外机构、律师事务所佣金试算");
        }

        //获取并封装佣金率值
        addEle(result);

        return result;
    }

    private void addEle(ColltTaskDistrVO item) {
        CooprOrgInfoVO cooprOrgInfoVO = new CooprOrgInfoVO();
        cooprOrgInfoVO.setCooprOrgNo(item.getOutsOrgCode());
        CooprOrgInfoVO rs = Optional.ofNullable(cooprOrgInfoService.queryByPk(cooprOrgInfoVO)).orElseGet(CooprOrgInfoVO::new);
        item.setCommRate(rs.getCommRate() == null ? "0" : rs.getCommRate().toString());
        item.setPrimCommRate(rs.getPrimCommRate() == null ? "0" : rs.getPrimCommRate().toString());
        item.setSecdCommRate(rs.getSecdCommRate() == null ? "0" : rs.getSecdCommRate().toString());
        item.setThdCommRate(rs.getThdCommRate() == null ? "0" : rs.getThdCommRate().toString());
        item.setLongAgeCommRate(rs.getLongAgeCommRate() == null ? "0" : rs.getLongAgeCommRate().toString());
        //item.setCooprOrgType(rs.getCooprOrgType());
    }


    /**
     * 分委外经手类型计算本次还款总计金额的总额
     *
     * @param colltTaskInfoVOList 催收任务信息
     * @param localDates 当前日期上一个月的起始日期、结束日期
     * @return
     */
    private Map<String, BigDecimal> getRepayTotalByHandType(List<ColltTaskInfoVO> colltTaskInfoVOList, LocalDate[] localDates) {
        Map<String, BigDecimal> result = new HashMap<>();

        for (String handType : allHandTypeList) {
            List<String> loanNos = colltTaskInfoVOList.stream()
                    .filter(ctivo -> {
                        return handType.equals(ctivo.getOutsHdleType());
                    })
                    .map(ColltTaskInfoVO::getLoanNo)
                    .collect(Collectors.toList());
            if (Objects.nonNull(loanNos)) {
                //获取不同手别的还款明细
                List<LoanRepayDetailVO> loanRepayDetailVOS = loanRepayDetailService.queryDataByLoanNos(loanNos);
                //根据【起始日期，结束日期】过滤，并累加 "本次还款总计金额"，得到回收总金额
                if (Objects.nonNull(loanRepayDetailVOS)) {
                    BigDecimal repayLmtTotal = getRepayTotalByDate(loanRepayDetailVOS, localDates[0].toString(), localDates[1].toString());
                    result.put(handType, repayLmtTotal);
                } else {
                    result.put(handType, BigDecimal.ZERO);
                }
            } else {
                result.put(handType, BigDecimal.ZERO);
            }
        }
        return result;
    }

    /**
     * 无手别计算本次还款总计金额的总额
     *
     * @param colltTaskInfoVOList 催收任务信息
     * @param localDates 当前日期的上一个月的起始日期、结束日期
     * @return
     */
    private BigDecimal getRepayTotal(List<ColltTaskInfoVO> colltTaskInfoVOList, LocalDate[] localDates) {
        BigDecimal result = BigDecimal.ZERO;
        List<String> loanNos = colltTaskInfoVOList.stream()
                .map(ColltTaskInfoVO::getLoanNo)
                .collect(Collectors.toList());
        if (Objects.nonNull(loanNos)) {
            //获取不同手别的还款明细
            List<LoanRepayDetailVO> loanRepayDetailVOS = loanRepayDetailService.queryDataByLoanNos(loanNos);
            //根据【起始日期，结束日期】过滤，并累加 "本次还款总计金额"，得到回收总金额
            if (Objects.nonNull(loanRepayDetailVOS)) {
                result = getRepayTotalByDate(loanRepayDetailVOS, localDates[0].toString(), localDates[1].toString());
            } else {
                logger.error("根据借据编号集:" + JSON.toJSONString(loanNos) + "，查询到的还款明细信息为空!");
            }
        }
        return result;
    }

    /**
     * 计算【开始日期，结束日期】 本次还款总计金额的总额
     *
     * @param loanRepayDetailVOS 还款明细信息集
     * @param strDate 开始日期
     * @param endDate 结束日期
     * @return
     */
    private BigDecimal getRepayTotalByDate(List<LoanRepayDetailVO> loanRepayDetailVOS, String strDate, String endDate) {
        return loanRepayDetailVOS.stream()
                .filter(loanRepayDetailVO -> {
                    return TimeUtil.compareDate(loanRepayDetailVO.getSetlValDt(), strDate) != -1 &&
                            TimeUtil.compareDate(loanRepayDetailVO.getSetlValDt(), endDate) != 1;
                })
                .map(LoanRepayDetailVO::getTotalAmt)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

}
